#!/usr/bin/env python
# coding: utf-8

# In[18]:


"""KMeans聚类法"""

get_ipython().run_line_magic('matplotlib', 'inline')

# import librarys
import numpy as np
import pandas as pd #用于读取csv文件
import matplotlib.pyplot as plt
import random


# 读取数据，存储为矩阵格式
M=np.array(pd.read_csv('D:/课程/jiqixuexi/dataset_circles.csv')) 
# 包含x、y、类别的矩阵
M1 = np.delete(M, -1, axis=1) 
# 去除类别列，成为散点坐标集合的矩阵形式




# k-means聚类算法

# 计算两个向量欧式距离
def distance(v1, v2):
    # v1、v2为两个向量
    d = np.sum(np.square(v1-v2))
    return d


# 初始化聚类中心
def centers(M1, k):
    # M1为数据样本，k为聚类个数
    n=np.shape(M1)[0] # 样本数量
    
    dI=list(range(n)) # 生成随机下标列表
    random.shuffle(dI)
    cI= dI[:k]
    return M1[cI, :] # 返回随机的聚类中心


# KMeans算法
def kmeans(M1, k):
    n = np.shape(M1)[0] # 样本数量
    
    # 初始化最近簇subcenters：存[簇序号,距离的平方] (n行 x 2列)
    subcenters = np.zeros((n, 2))

    # 调用随机中心点函数初始化聚类中心点
    centres = centers(M1, k)
    print('初始聚类中心=', centres)

    N = 0
    
    while True:   
        # 标志位clusterChanged初始置False
        clusterChanged = False
    
        # 将样本点分配到最近的聚类中心对应簇中
        for i in range(n):
            mindis = np.inf;
            minInd = -1
            for j in range(k):
                # 计算第i个样本到第j个中心点的距离
                dist = distance(centres[j, :], M1[i, :])
                if dist < mindis:
                    mindis = dist
                    minInd = j
                    
            # 样本上次分配结果跟本次不一样，标志位clusterChanged置True
            if subcenters[i, 0] != minInd:
                clusterChanged = True
            subcenters[i, :] = minInd, mindis ** 2  # 分配样本到最近的簇
            
        N += 1
        sse = sum(subcenters[:, 1])
        print('第%d' % N + '次迭代的误差平方和为 %f' % sse)
        
        # 更新聚类中心
        for cent in range(k):  # 样本分配结束后，重新计算聚类中心
            pC = M1[subcenters[:, 0] == cent, :]
            centres[cent, :] = np.mean(pC, axis=0)
        
        # 如果聚类重心没有发生改变，则退出迭代
        if not clusterChanged:
            break
            
    return centres, subcenters


# 进行k-means聚类
k = 2  # 聚类数定义为2
center, subcenter = kmeans(M1, k)





# 二维空间显示聚类结果
def kmeansshow(dataSet, k, center, subcenter):  
    n, d = np.shape(dataSet)  # 样本数n ,维数d

    if d != 2:
        print('sorry,the dimension of your dataset is not 2!')
        return 1
    mark = ['or', 'ob', 'og', 'ok', '^r', '^b', '<g']  # 样本图形标记
    if k > len(mark):
        print('sorry,your k is too large,please add length of the marksample!')
        return 1
    
    # 绘所有样本
    for i in range(n):
        marki = int(subcenter[i, 0])  # 矩阵形式转为int值, 簇序号
        # 特征维对应坐标轴x,y；样本图形标记及大小
        plt.plot(dataSet[i, 0], dataSet[i, 1], mark[marki], markersize=6)

    # 绘中心点
    markcenter = ['o', '*']  # 聚类中心图形标记
    label = ['0', '1']
    c = ['yellow', 'pink']
    for i in range(k):
        plt.plot(center[i, 0], center[i, 1], markcenter[i], markersize=15, label=label[i], c=c[i])
        plt.legend(loc='upper left')  #图例
    plt.xlabel('feature 1')
    plt.ylabel('feature 2')

    plt.title('k-means cluster result')  # 标题
    plt.show()
    
    
# 画出实际图像
#分类
x0=[] # 类别为0
y0=[] 
x1=[] # 类别为1
y1=[]
x=[]  # 数据整体
y=[]
for a in M:
    if a[2]==1:   # 类别 1 为一簇
        x1.append(a[0])
        y1.append(a[1])
        x.append(a[0])
        y.append(a[1])
    elif a[2]==0: # 类别 0 为一簇
        x0.append(a[0])
        y0.append(a[1])
        x.append(a[0])
        y.append(a[1])
        
#显示
plt.figure()
plt.scatter(x0,y0,c='red', label = 'bad')
plt.scatter(x1,y1,c='green', label = 'good')
plt.xlabel('feature 1')
plt.ylabel('feature 2')
plt.title('true figure') 
plt.show()
    
# 聚类绘图显示
kmeansshow(M1, k, center, subcenter)


# In[ ]:




